interface ArrifyType<ValueType> {
  (value: ValueType): ValueType extends (null | undefined)
    ? []
    : ValueType extends string
    ? [string]
    : ValueType extends readonly unknown[]
    ? ValueType
    : ValueType extends Iterable<infer T>
    ? T[]
    : [ValueType];
}

export const arrify: ArrifyType<any> = <T>(value: T): Array<T> => {
  if (value === null || value === undefined) {
    return []
  }

  if (Array.isArray(value)) {
    return value
  }

  if (typeof value === 'string') {
    return [value]
  }

  if (typeof (value as unknown as Iterable<any>)[Symbol.iterator] === 'function') {
    return [...value as any]
  }

  return [value]
}
